/**
 * 
 */
package ywu.tools.timesync.ntp;

import java.text.DateFormat;
import java.text.SimpleDateFormat;

/**
 * <pre>
 * 0    1     4     7         15         23         31
 * +----+-----+-----+----------+----------+----------+
 * | LI |  VN | Mode| Statum   | Poll     |Preciscion|
 * +----+-----+-----+----------+----------+----------+
 * |          Root delay(32 bits)                    |
 * ---------------------------------------------------
 * |          Root despersion(32 bits)               |
 * ---------------------------------------------------
 * |          Reference identifier(32 bits)          |
 * ---------------------------------------------------
 * |                                                 |
 * |          Reference timestamp(64 bits)           |
 * ---------------------------------------------------
 * |                                                 |
 * |          Originate timestamp(64 bits)           |
 * ---------------------------------------------------
 * |                                                 |
 * |          Receive timestamp(64 bits)             |
 * ---------------------------------------------------
 * |                                                 |
 * |          Transmit timestamp(64 bits)            |
 * ---------------------------------------------------
 * |                                                 |
 * |                                                 |
 * |          Authenticator timestamp(96 bits)       |
 * ---------------------------------------------------
 * </pre>
 * 
 * @author ywu
 */
public abstract class NtpDatagram
{
    private static final long DIFF_EPOCHS = 2208988800L; // 1900 - 1970 1.1的秒数

    protected static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS Z");

    /**
     * LI（Leap Indicator）：长度为2比特，值为“11”时表示告警状态，时钟未被同步。为其他值时NTP不做处理
     */
    protected byte leapIndicator;

    /**
     * VN（Version Number）：长度为3比特，表示NTP的版本号，目前的最新版本为3。
     */
    protected byte version = 3;

    /**
     * Mode：长度为3比特，表示NTP的工作模式。不同的值所表示的含义分别是：0未定义、1表示主动对等体模式、2表示被动对等体模式、3表示客户模式、4表示服务器模式、5表示广播模式或组播模式、6表示此报文为NTP控制报文、7
     * 预留给内部使用。
     */
    protected byte mode;

    /**
     * Originate Timestamp：NTP请求报文离开发送端时发送端的本地时间。
     */
    protected long originateTimestamp;

    /**
     * 本地到主参考时钟源的往返时间
     */
    protected int rootDelay;

    /**
     * 参考时钟返回的时间
     */
    protected long referenceClock;

    /**
     * Server接受到请求报文的时间
     */
    protected long receiveTimestamp;

    /**
     * Server发出回应报文的时间
     */
    protected long transmitTimestamp;

    /**
     * VN（Version Number）：长度为3比特，表示NTP的版本号，目前的最新版本为3。
     * 
     * @return
     */
    public byte getVersion()
    {
        return version;
    }

    /**
     * VN（Version Number）：长度为3比特，表示NTP的版本号，目前的最新版本为3。
     * 
     * @param version
     */
    public void setVersion(final byte version)
    {
        this.version = version;
    }

    /**
     * NTP请求报文离开发送端时发送端的本地时间。
     * 
     * @return
     */
    public long getOriginateTimestamp()
    {
        return originateTimestamp;
    }

    /**
     * LI（Leap Indicator）：长度为2比特，值为“11”时表示告警状态，时钟未被同步。为其他值时NTP不做处理
     * 
     * @return
     */
    public byte getLeapIndicator()
    {
        return leapIndicator;
    }

    /**
     * Mode：长度为3比特，表示NTP的工作模式。不同的值所表示的含义分别是：0未定义、1表示主动对等体模式、2表示被动对等体模式、3表示客户模式、4表示服务器模式、5表示广播模式或组播模式、6表示此报文为NTP控制报文、7
     * 预留给内部使用。
     * 
     * @return
     */
    public byte getMode()
    {
        return mode;
    }

    /**
     * 本地到主参考时钟源的往返时间
     * 
     * @return
     */
    public int getRootDelay()
    {
        return rootDelay;
    }

    /**
     * 参考时钟返回的时间
     * 
     * @return
     */
    public long getReferenceClock()
    {
        return referenceClock;
    }

    /**
     * Server接受到请求报文的时间
     * 
     * @return
     */
    public long getReceiveTimestamp()
    {
        return receiveTimestamp;
    }

    /**
     * Server发出回应报文的时间
     * 
     * @return
     */
    public long getTransmitTimestamp()
    {
        return transmitTimestamp;
    }

    protected static long toNtpTimestamp(final long ts)
    {
        long ntpTs = ts / 1000 + DIFF_EPOCHS;
        ntpTs <<= 32;
        return ntpTs;
    }

    protected static long fromNtpTimestamp(final long ntpTs)
    {
        //        System.out.println(Long.toBinaryString(ntpTs));
        long seconds = ntpTs >>> 32;
        long fraction = ntpTs & 0xFFFFFFFFL;
        //        System.out.println(Long.toBinaryString(seconds) + ", " + Long.toBinaryString(fraction));
        long ts = (seconds - DIFF_EPOCHS) * 1000;
        ts += fraction * 1000 / 4294967296L;

        //        System.out.println(DATE_FORMAT.format(new Date(ts)));
        return ts;
    }
}
